<?php
declare(strict_types=1);

namespace Dreamcat\Http\EnhanceClient\Cases;

use Dreamcat\Http\EnhanceClient\Exception\Error;
use Dreamcat\Http\EnhanceClient\Impl\GuzzleHttpClient;
use Zend\Diactoros\RequestFactory;
use Zend\Diactoros\ResponseFactory;
use Zend\Diactoros\StreamFactory;
use PHPUnit\Framework\TestCase;
use Psr\Http\Client\ClientExceptionInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

/**
 * 测试客户端
 * @author vijay
 * @todo 后面有空把启动http server做成脚本部分
 * @todo 目前测试时需要 php -S 127.0.0.1:8080 -t ../resource/httpserver
 */
class ClientTest extends TestCase
{
    /** @var RequestFactory 请求创建工厂 */
    private $requestFactory;
    /** @var ResponseFactory 响应创建工厂 */
    private $responseFactory;
    /** @var StreamFactory 流创建工厂 */
    private $streamFactory;

    /**
     * ClientTest constructor.
     * @param null $name -
     * @param array $data -
     * @param string $dataName -
     */
    public function __construct($name = null, array $data = [], $dataName = '')
    {
        parent::__construct($name, $data, $dataName);
        $this->requestFactory = new RequestFactory();
        $this->responseFactory = new ResponseFactory();
        $this->streamFactory = new StreamFactory();
    }

    /**
     * -
     * @param RequestInterface $request
     * @param ResponseInterface $expect
     * @return void
     * @throws \Psr\Http\Client\ClientExceptionInterface
     * @dataProvider normalData
     */
    public function testNormal(RequestInterface $request, ResponseInterface $expect)
    {
        $client = new GuzzleHttpClient();
        $response = $client->sendRequest($request);
        self::assertEquals($expect->getStatusCode(), $response->getStatusCode());
        self::assertEquals($expect->getBody()->getContents(), $response->getBody()->getContents());
    }

    /**
     * 常规测试数据
     * @return array
     */
    public function normalData()
    {
        return [
            [
                $this->requestFactory->createRequest("GET", "http://127.0.0.1:8080/ok.php"),
                $this->responseFactory->createResponse(200)
                    ->withBody($this->streamFactory->createStream("测试通过的字符串")),
            ],
            [
                $this->requestFactory->createRequest("GET", "http://127.0.0.1:8080/404.php"),
                $this->responseFactory->createResponse(404),
            ],
        ];
    }

    public function testTimeout()
    {
        $client = new GuzzleHttpClient();
        $req = $this->requestFactory->createRequest("GET", "http://127.0.0.1:8080/timeout.php");

        try {
            $client->sendRequest($req, 100);
        } catch (ClientExceptionInterface $e) {
            self::assertEquals(Error::class, get_class($e));
            $preg = "#^cURL error 28: Operation timed out after (?<t>\\d+) milliseconds with 0 bytes received#";
            self::assertEquals(1, preg_match($preg, $e->getMessage(), $match), "异常消息与预期不一致: {$e->getMessage()}");
            self::assertTrue(abs($match["t"] - 100) <= 5, "超时控制差距过大");
            # 这里要确保远程服务器的timeout.php执行完成
            sleep(3);
        }
    }

    /**
     * 测试先行设置超时时间的情况
     * @return void
     * @throws ClientExceptionInterface
     */
    public function testSetTimeout()
    {
        $client = new GuzzleHttpClient();
        $client->setTimeOutMs(1000);
        $req = $this->requestFactory->createRequest("GET", "http://127.0.0.1:8080/timeout.php?t=0");
        $response = $client->sendRequest($req);
        self::assertEquals(200, $response->getStatusCode());
        self::assertEquals("time out, 0", $response->getBody()->getContents());
    }
}

# end of file
